/** @file
@brief Desclarations related to #PrynValue. */
#ifndef PRYN_VALUE_H
#define PRYN_VALUE_H

typedef struct PrynValue PrynValue; ///< An instance of a type.
typedef PrynDList (PrynValue) PrynValueList; ///< A list of values.

#include <pryn/platform.h>
#include <pryn/result.h>
#include <pryn/tag.h>
#include <pryn/type.h>

/** @defgroup PrynValue PrynValue C API
	@{
	@}
*/

/** @addtogroup PrynValue
	@{ */

PrynImport (PrynResult, prynValueCreate, (PrynValue **value, PrynType *type, void *initial)) ///< Create a new value of the type.
PrynImport (PrynResult, prynValueCreateFromId, (PrynValue **value, PrynState *state, const PrynString *id, void *initial)) ///< Find the type with the given id in the state, then create a value for it.
PrynImport (PrynResult, prynValueDestroy, (PrynValue *value)) ///< Destroy the value, freeing all of its data, then clear the value

PrynImport (PrynResult, prynValueDisassociate, (PrynValue *value)) ///< Call the destructor on the value then neuter it by nulling its type and pointer parameters. This makes it so that the only valid function that can be performed on it is to destroy it.

PrynImport (PrynResult, prynValueAllocate, (PrynValue **value, PrynType *type, size_t length, void *initial))
	/**< Allocate a value of this type. This is for implementation of types.

	@param[out] value Written with the newly created value or 0 on failure.
	@param type The type to assign.
	@param length The number of bytes to allocate into the pointer field of the result.
	@param initial If non-zero, this is used as the initial value of the pointer array; otherwise it's all zeroes.
	@returns #PrynResultSuccess or a #PrynResult error code. */

PrynImport (PrynResult, prynValueConnectionImage, (PrynValue *value, int width, int height, PrynColor *image, PrynColor *fallback)) ///< Read the connection image for this value. Both @e image and @e fallback can be zero. The image is in [x + y * @e width] order, and gets closer to the input pin as it increases vertically. The left-to-right axis is perpendicular to the connection line. The @e fallback is in case the @e image cannot be supported, and is a single color to use for the connection. If type is zero, in addition to returning #PrynResultNullArgument this clears the @e image and @e fallback to red.
PrynImport (PrynResult, prynValueColors, (PrynValue *value, PrynColor *outer, PrynColor *inner)) ///< Retrieve the inner and outer colors to use when rendering a pin carrying this value.

PrynImport (PrynResult, prynValueState, (PrynValue *value, PrynState **output)) ///< State the value is created within.
PrynImport (PrynResult, prynValueType, (PrynValue *value, PrynType **output)) ///< The type the value is an instance of, or 0 if this is disassociated.
PrynImport (PrynResult, prynValuePointer, (PrynValue *value, void **output)) ///< Retrieve the pointer to the value's data.

#ifdef PrynInternalStructs
/** @brief An instance of a type.
*/
struct PrynValue
{
#ifdef PrynInternal
	PrynValue *pNext; ///< Next instance of this value in the type, or 0 if this is the last or disassociated.
	PrynValue *pPrevious; ///< Previous instance of this value in the type, or 0 if this is the first or disassociated.

	PrynState *pState; ///< State the value exists within.
	PrynType *pType; ///< The type of the value.
	void *pPointer; ///< Pointer to the data of the value. This is normally immediately after the struct itself.
#endif /* PrynInternal */

#if __cplusplus
	static inline PrynValue *Create (PrynType *type, void *initial = 0) { PrynValue *output; type->checkError (prynValueCreate (&output, type, initial)); return output; }  ///< Create a new instance of this type.
	static inline PrynValue *Create (PrynState *state, const PrynString &id, void *initial = 0); ///< Find the type with the given id in the state, then create a value for it.
	static inline PrynValue *Allocate (PrynType *type, size_t length = 0, void *initial = 0) { PrynValue *output; type->checkError (prynValueAllocate (&output, type, length, initial)); return output; } 
		/**< Allocate a value of this type. This is for implementation of types.

		@param type The type to assign.
		@param length The number of bytes to allocate into the pointer field of the result.
		@param initial If non-zero, this is used as the initial value of the pointer array; otherwise it's all zeroes.
		@returns The newly created value. */

	inline PrynResult checkError (PrynResult result) { return prynCheckErrorBase (state (), result); } ///< If the result is below zero, throw an error.

	inline void destroy () { prynValueDestroy (this); } ///< Destroy the value, freeing all of its data. This also clears the value to empty.

	inline void connectionImage (int width, int height, PrynColor *image, PrynColor *fallback) { checkError (prynValueConnectionImage (this, width, height, image, fallback)); } ///< Read the connection image for this value. Both @e image and @e fallback can be zero. The image is in [x + y * @e width] order, and gets closer to the input pin as it increases vertically. The left-to-right axis is perpendicular to the connection line. The @e fallback is in case the @e image cannot be supported, and is a single color to use for the connection. If type is zero, in addition to returning #PrynResultNullArgument this clears the @e image and @e fallback to red.

	inline void colors (PrynColor *outer, PrynColor *inner) { checkError (prynValueColors (this, outer, inner)); } ///< Retrieve the inner and outer colors to use when rendering a pin 

	inline PrynState *state () { PrynState *output; prynCheckErrorNull (prynValueState (this, &output)); return output; } ///< The state the value is created within.
	inline PrynType *type () { PrynType *output; checkError (prynValueType (this, &output)); return output; } ///< The type the value is an instance of, or 0 if this is disassociated.
	inline void *pointer () { void *output; checkError (prynValuePointer (this, &output)); return output; } ///< Retrieve the pointer to the value's data.

#endif /* __cplusplus */
};
#endif /* PrynInternalStructs */

/** @} */ // (group)

#endif /* PRYN_VALUE_H */
